#include "PDAServer.h"
#include <iostream>



#define DEFAULT_BUFLEN 512

using namespace std;
using namespace server;

PDAServer* PDAServer::m_instance = new PDAServer;

PDAServer::PDAServer(void): ListenSocket(INVALID_SOCKET), 
							ClientSocket(INVALID_SOCKET),
							commandSocket(INVALID_SOCKET), 
							clientCommandSocket(INVALID_SOCKET),
							callbackSocket(INVALID_SOCKET),
							clientCallbackSocket(INVALID_SOCKET)
{
	start();
	acceptPDA();
}

PDAServer::~PDAServer(void) throw () {
}

PDAServer* PDAServer::getInstance() {
	return m_instance;
}

void PDAServer::sendCallback(Callback* pcb) {
	cout << "calback sent" << endl;
	char* data = pcb->serialize();
//	data[18] = '\n';
	send(this->clientCallbackSocket, data, 20, 0);
}

int PDAServer::startRTIservices(const char* port)
{
	cout << "RTIservices starting on port: " << port << endl;
	WSADATA wsaData;

    struct addrinfo *result = NULL,
                    hints;
    char recvbuf[DEFAULT_BUFLEN];
    int  iResult,
         recvbuflen = DEFAULT_BUFLEN;
    

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
	iResult = getaddrinfo(NULL, port, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
	this->commandSocket = ListenSocket;
}
int PDAServer::startCallbackServices(const char* port)
{
	cout << "CallbackServices starting on port: " << port << endl;
	WSADATA wsaData;

    struct addrinfo *result = NULL,
                    hints;
    char recvbuf[DEFAULT_BUFLEN];
    int  iResult,
         recvbuflen = DEFAULT_BUFLEN;
    

    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2,2), &wsaData);
    if (iResult != 0) {
        printf("WSAStartup failed: %d\n", iResult);
        return 1;
    }

    ZeroMemory(&hints, sizeof(hints));
    hints.ai_family = AF_INET;
    hints.ai_socktype = SOCK_STREAM;
    hints.ai_protocol = IPPROTO_TCP;
    hints.ai_flags = AI_PASSIVE;

    // Resolve the server address and port
	iResult = getaddrinfo(NULL, port, &hints, &result);
    if ( iResult != 0 ) {
        printf("getaddrinfo failed: %d\n", iResult);
        WSACleanup();
        return 1;
    }

    // Create a SOCKET for connecting to server
    ListenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol);
    if (ListenSocket == INVALID_SOCKET) {
        printf("socket failed: %ld\n", WSAGetLastError());
        freeaddrinfo(result);
        WSACleanup();
        return 1;
    }

    // Setup the TCP listening socket
    iResult = bind( ListenSocket, result->ai_addr, (int)result->ai_addrlen);
    if (iResult == SOCKET_ERROR) {
        printf("bind failed: %d\n", WSAGetLastError());
        freeaddrinfo(result);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    freeaddrinfo(result);

    iResult = listen(ListenSocket, SOMAXCONN);
    if (iResult == SOCKET_ERROR) {
        printf("listen failed: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

	this->callbackSocket = ListenSocket;
}

int PDAServer::start()
{
	startRTIservices("3000");
	startCallbackServices("3001");

	return TRUE;
}

int PDAServer::acceptPDA() {
	printf("waiting for pda...");
	// Accept a client socket
	ClientSocket = accept(this->commandSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
	this->clientCommandSocket = ClientSocket;

	ClientSocket = accept(this->callbackSocket, NULL, NULL);
    if (ClientSocket == INVALID_SOCKET) {
        printf("accept failed: %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
	this->clientCallbackSocket = ClientSocket;
	printf("pda client connected\n");
    // No longer need server socket
    closesocket(this->commandSocket);	
    closesocket(this->callbackSocket);	
}

RTICommand* PDAServer::getCommand() {
	char recvbuf[DEFAULT_BUFLEN];
    int  iResult, recvbuflen = DEFAULT_BUFLEN;

//	iResult = recv(this->clientCommandSocket, recvbuf, recvbuflen, 0);
//	cout<< "read from pda: " << recvbuf<<endl;
	RTICommand* comm = RTICommand::newCommand(recvbuf);

	return comm;
}

int main4()
{
	PDAServer* s = PDAServer::getInstance();
	s->acceptPDA();
	RTICommand* comm = s->getCommand();
	comm->process();

//	s->sendCallback(new Callback(DISCOVER_OBJECT_INSTANCE));

	return 0;
}

